#pragma once

#include "Containers/Optional.h"
#include "Containers/Map.h"
#include "Containers/Any.h"
#include "Reflection.h"

#include "Containers/String.h"

#include "PropertyFieldInterface.h"
#include "PropertyGetSetInterface.h"
#include "PropertyScriptInterface.h"
#include "DecoratedType.h"

class CPropertyList;
class CType;

class WHENGINE_API CProperty
{
public:	
	CProperty(
		CPropertyList* InParentList
		,CString InName
		,const SDecoratedType& InType
		,TMap<EPropertyFlags,  SReflectionMetaDataValue> InMetaData
		);

	virtual ~CProperty();

	CString GetName()  { return Name; };

	//value type
	const SDecoratedType& GetType() {return Type;}

	//owner object type
	CType* GetOwnerType(); 

	//for non static property, Getting non static property value need a object pointer
	//confilict with StaticProperty, only one of them can be not null
	INonStaticProperty* NonStaticProperty=nullptr;

	//for static property, Getting static property value do not need object pointer
	//confilict with NonStaticProperty, only one of them can be not null
	IStaticProperty* StaticProperty=nullptr;

	//for field property, field property's value is the pointer to the member variable 
	IFieldProperty* FieldProperty=nullptr;

	//only for judge if this property is a script property
	IScriptProperty* ScriptProperty=nullptr;

	//only valid for native field property
	//if not a native field property, return -1
	virtual int64_t GetNativeFieldOffset() const  { return -1;}

	bool IsField() const { return FieldProperty!=nullptr; }
	bool IsStatic() const { return StaticProperty!=nullptr; }
	bool IsScript() const { return ScriptProperty!=nullptr; }
	bool IsNativeField() const { return GetNativeFieldOffset()!=-1; }

	TMap<EPropertyFlags,  SReflectionMetaDataValue> GetMetaData() const { return MetaData; }	
	bool HasFlag(EPropertyFlags InFlag)
	{
		return MetaData.Contains(InFlag);
	}

	bool IsTypeSupportScript() const
	{
		return Type.BasicType->CanUseInScript();
	}

	bool CanUseInScript() ;
protected:
	SDecoratedType Type=nullptr;
	CString Name;
	TMap<EPropertyFlags,  SReflectionMetaDataValue> MetaData;
	CPropertyList* ParentList=nullptr;
};